/*
 *  Axolotl - Alternate persistence for Grails
 *  Copyright (C) 2008  Juanjo García Latre
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package com.googlecode.axolotl.jdbc;

import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;

import com.googlecode.axolotl.query.Query;


public class SpringJdbcDatabase extends AbstractJdbcDatabase {

	private JdbcTemplate jdbcTemplate;
	
	
	public void setDataSource(DataSource dataSource) {
		super.setDataSource(dataSource);
		jdbcTemplate = new JdbcTemplate(dataSource);
	}


	public Object load(Class clazz, Object id) {
		final Converter converter = getSqlFactory().getConverter(clazz);
		final String sql = getSqlFactory().getSelectRow(clazz);
		try {
			return jdbcTemplate.queryForObject( sql, 
					new Object[] {id}, 
					converter.getEntityReader( getTargetDatabase() ) );
		}
		catch (EmptyResultDataAccessException e) {
			for (Class subclass: converter.getSubClasses()) {
				Object result = load(subclass, id);
				if (result != null) {
					return result;
				}
			}
			return null;
		}
	}

	
	public int count(Query query) {
		return count( query.getType(), query.getFilter() );
	}

	
	public List loadIds(Query query) {
		return loadIds( query.getType(), query.getFilter(), query.getOrder() );
	}
	
	
	public void insert(Object entity) {
		Class clazz = entity.getClass();
		final Converter converter = getSqlFactory().getConverter(clazz);
		jdbcTemplate.update( converter.getInsertStatementCreator(entity) );
	}
	
	
	public void update(Object entity) {
		Class clazz = entity.getClass();
		final Converter converter = getSqlFactory().getConverter(clazz);
		jdbcTemplate.update( converter.getUpdateStatementCreator(entity) );
	}
	
	
	public void delete(Object entity) {
		Class clazz = entity.getClass();
		final Converter converter = getSqlFactory().getConverter(clazz);
		jdbcTemplate.update( converter.getDeleteStatementCreator(entity) );
	}
	
	
	
	private int count(Class clazz, Object filter) {
		final String sql = getSqlFactory().getSelectCount(clazz, filter);
		int c = jdbcTemplate.queryForInt(sql);
		for (Class subclass: getSqlFactory().getConverter(clazz).getSubClasses()) {
			c += count(subclass, filter);
		}
		return c;
	}

	
	@SuppressWarnings("unchecked")
	private List loadIds(Class clazz, Object filter, Object order) {
		final Converter converter = getSqlFactory().getConverter(clazz);
		final String sql = getSqlFactory().getSelectIds(clazz, filter, order);
		List ids = jdbcTemplate.query(sql, converter.getIdReader());
		Class[] subClasses = converter.getSubClasses();
		if (subClasses.length > 0) {
			ids = new ArrayList(ids);
			for (Class subclass: subClasses) {
				ids.addAll( loadIds(subclass, filter, order) );
			}
		}		
		return ids;
	}

}
